/**
 * @file tiny_ring_queue.c
 * @brief 环形队列实现
 * @author 张恒宣 
 * @LastEditTime 2024/9/22
 * 
 * MIT License
 *
 * Copyright (c) 2025 张恒宣 luckkeymail@163.com
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

/*********************
 *      头文件
 *********************/

#include "tiny_ring_queue.h"
#include "tiny_malloc.h"

/*********************
*      私有函数 
*********************/

/// @brief 初始化环形队列
/// @param rq 待初始化的环形队列
/// @param block_num 块数量
/// @param block_size 块大小
/// @param queue_data_copy 拷贝策略
/// @return 
static int tiny_ring_queue_init(tiny_ring_queue_t *rq, tiny_uint32_t block_num, tiny_uint32_t block_size, tiny_rq_copy_callback queue_data_copy)
{
	rq->block_num = block_num + 1;
	rq->block_size = block_size;
	rq->buf = (tiny_uint8_t *)tiny_malloc(rq->block_num * block_size);
	rq->queue_data_copy = queue_data_copy;
	if (!rq->buf)
	{
		return 0;
	}
	rq->head = 0;
	rq->tail = 0;
	return 1;
}

/*********************
*      公共函数 
*********************/

/// @brief 默认提供的拷贝策略, 按字节拷贝
/// @param dst 目标地址
/// @param src 源地址
/// @param size 拷贝大小
void tiny_queue_buf_data_copy(tiny_uint8_t *dst, tiny_uint8_t *src, tiny_uint32_t size)
{
	for (tiny_uint32_t i = 0; i < size; i++)
	{
		dst[i] = src[i];
	}
}

/// @brief 默认提供的拷贝策略, 按值拷贝
/// @param dst 目标地址
/// @param src 源地址
/// @param size 拷贝大小
void tiny_queue_int64_data_copy(tiny_uint8_t *dst, tiny_uint8_t *src, tiny_uint32_t size)
{
	*(long long int *)(void*)dst = *(long long int *)(void*)src;
	UNUSED_PARAMETER(size);
}

/// @brief 创建环形队列
/// @param block_num 块数量
/// @param block_size 块大小
/// @param queue_data_copy 拷贝策略
/// @return 
tiny_ring_queue_t *tiny_ring_queue_create(tiny_uint32_t block_num, tiny_uint32_t block_size, tiny_rq_copy_callback queue_data_copy)
{
	tiny_ring_queue_t *rq = (tiny_ring_queue_t *)tiny_malloc(sizeof(tiny_ring_queue_t));
	if (!rq)
	{
		return tiny_null;
	}
	if (!tiny_ring_queue_init(rq, block_num, block_size, queue_data_copy))
	{
		tiny_free(rq);
		return tiny_null;
	}

	return rq;
}

/// @brief 释放环形队列
/// @param rq 待释放的环形队列
void tiny_ring_queue_free(tiny_ring_queue_t *rq)
{
	if (!rq)
	{
		return;
	}
	tiny_free(rq->buf);
	tiny_free(rq);
}

/// @brief 队列是否为空
/// @param rq 待判断的队列
/// @return 1不为空, 0为空
tiny_int32_t tiny_ring_queue_isempty(tiny_ring_queue_t *rq)
{
	if (!rq)
	{
		return -1;
	}
	return rq->head == rq->tail;
}

/// @brief 压入数据
/// @param rq 待压入的队列
/// @param buf 待压入的数据
/// @param size 数据大小
/// @return 执行状态
QUEUE_RET_STATUS tiny_ring_queue_push(tiny_ring_queue_t *rq, tiny_uint8_t *buf, tiny_uint32_t size)
{
	if (!rq || !buf || size > rq->block_size)
	{
		return QUEUE_ERROR;
	}

	int temp = rq->tail + 1;
	temp %= rq->block_num;

	if (temp == rq->head)
	{
		return QUEUE_FULL;
	}

	rq->queue_data_copy(rq->buf + (tiny_int32_t)rq->block_size * rq->tail, buf, size);
	rq->tail = temp;
	return QUEUE_OK;
}

/// @brief 弹出数据
/// @param rq 待弹出的队列
/// @param buf 存储弹出数据的存储区
/// @param size 存储区大小
/// @return 
QUEUE_RET_STATUS tiny_ring_queue_pop(tiny_ring_queue_t *rq, tiny_uint8_t *buf, tiny_uint32_t size)
{
	if (!rq || !buf || size <= 0 || size > rq->block_size)
	{
		return QUEUE_ERROR;
	}

	if (rq->tail == rq->head)
	{
		return QUEUE_EMPTY;
	}

	rq->queue_data_copy(buf, rq->buf + (tiny_int32_t)rq->block_size * rq->head, size);
	rq->head++;
	rq->head %= rq->block_num;
	return QUEUE_OK;
}
